import { Injector, OnInit, OnDestroy, DoCheck } from '@angular/core';
import { Router } from '@angular/router';
import * as _ from 'lodash';
import { Subscription } from 'rxjs/internal/Subscription';
import { timeout } from 'rxjs/operators';
import { ApiService } from '@core/api.service';
import { NzMessageService } from 'ng-zorro-antd';
import { UpdateMessageService } from '@core/update-message.service';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment';

export abstract class UniversalTablesUtil implements OnInit, DoCheck, OnDestroy {
  apiService: ApiService;
  message: NzMessageService;
  ums: UpdateMessageService;
  router: Router;
  domSanitizer: DomSanitizer;
  http: HttpClient;

  displayData = [];
  loadingData = true;
  allChecked = false;
  indeterminate = false;
  // 根据此项判断接口
  apiIdentity: string;
  singleRecordKeys: string[];
  recognition: string;
  searchKeys: string[];
  typeTreeData;
  warehouseTreeData;
  selectedDataLen: number;
  // 子组件返回搜索关键字，要存储
  params: { string?: string } = {};
  itemsTotal: number;
  pageIndex = 1;
  pageSize = 10;
  oldSize = 10;
  typePlaceHolder = '物资种类筛选';
  warehousePlaceHolder = '仓库筛选';
  allowEdit = true;
  sortName: string;
  sortValue: string;
  statusList: string[] = ['已下发', '已签收', '已拒收'];
  // 方便筛选的选项
  convenienceDataC: any[];
  convenienceDataW: any[];
  isGetAll = false;
  // 保证物资入库后返回能正确获取物资数
  subscription: Subscription;
  // 防止反复获取
  isUpdate = true;
  sortKey = 'order';
  rowspan = 'rs_';
  mergeColumns: string[] = [];
  statusInd = 'status';
  _sub: Subscription;

  constructor(private baseInjector: Injector) {
    this.apiService = this.baseInjector.get(ApiService);
    this.message = this.baseInjector.get(NzMessageService);
    this.ums = this.baseInjector.get(UpdateMessageService);
    this.router = this.baseInjector.get(Router);
    this.domSanitizer = this.baseInjector.get(DomSanitizer);
    this.http = this.baseInjector.get(HttpClient);
  }

  ngOnInit() {
    this.apiIdentity = this.router.url.substr(1).split(/\W/)[0];
    this.getMainData(this.pageSize, this.pageIndex, this.params);
    this.getSubData();
  }

  getState = (state: boolean): boolean => this.loadingData = state;

  // 标签正常化显示
  normalizeTag = (rawHTML: string): SafeHtml => this.domSanitizer.bypassSecurityTrustHtml(rawHTML);

  // 只能选中一条
  checkOne = (ind: number): void => this.displayData.forEach((data, k: number) => data.checked = ind == k);

  // 可以选中多条
  checkAll(value: boolean): void {
    this.displayData.forEach(data => data.checked = value);
    this.refreshStatus();
  }

  refreshStatus(): void {
    const displayData = this.displayData;
    if (displayData) {
      const allChecked = displayData.every(value => value.checked);
      const allUnChecked = displayData.every(value => !value.checked);
      this.selectedDataLen = displayData.filter(v => v.checked).length;
      this.allChecked = allChecked;
      this.indeterminate = (!allChecked) && (!allUnChecked);
    }
  }

  goInnerPage(href: string, data = {}) {
    this.isUpdate = true;
    this.router.navigate([href], { queryParams: data }).then();
  }

  // 撤销单条数据
  delOneMaterial() {
    const displayData = this.displayData;
    if (displayData.some(data => data.checked)) {
      for (let i = displayData.length - 1; i >= 0; i--) {
        const data = displayData[i];
        if (data.checked) {
          this.withdrawDAOne({ batchId: data.BATCH_ID || '' }).subscribe((res: any) => {
            const resType = res.type;
            const resMessage = res.message || '';
            if (resType == 'success') {
              this.message.create('success', resMessage, { nzDuration: 1500 });
              this.getMainData(this.pageSize, this.pageIndex, this.params);
            } else if (resType == 'fail') {
              this.message.create('warning', resMessage);
              data.checked = false;
            }
          }, err => this.errorHandle(err));
          break;
        }
      }
    } else {
      this.message.warning('请选择待撤销条目！', { nzDuration: 1000 });
    }
  }

  // 撤销单条下发或调拨数据
  withdrawDAOne(param) {
    const url = environment.apiBase + '/csmis/mtd/back.jwt';
    return this.http.post(url, '', param);
  }

  // 删除多条数据
  delMaterials(accordingStatus = false) {
    if (this.allChecked || this.indeterminate) {
      const recognition = this.recognition;
      const delGoods = this.displayData.filter(data => data.checked);
      let delGoodsOrders: string[];
      const delList: string[] = [];
      if (accordingStatus) {
        delGoodsOrders = delGoods.filter(data => data[this.statusInd] == '0').map(data => data[recognition]);
        delGoods.filter(data => data[this.statusInd] != '0').forEach(data => data.checked = false);
        this.refreshStatus();
        this.message.warning('只可删除修改中的条目！', { nzDuration: 1200 });
        if (!delGoodsOrders.length) {
          return;
        }
      } else {
        delGoodsOrders = delGoods.map(data => data[recognition]);
      }
      this.displayData.forEach(data =>
        delGoodsOrders.includes(data[recognition]) && delList.push(data)
      );
      this.loadingData = true;
      this.apiService.delMaterialsData(this.apiIdentity, delList.map(data => data[recognition]))
        .subscribe(res => {
          this.remoteMessage(res);
        }, err => this.errorHandle(err));
      setTimeout(() => this.loadingData = false, 4500);
    } else {
      this.message.create('warning', '请勾选待删除条目！', { nzDuration: 1200 });
    }
  }

  // 主表格数据获取与更新
  getMainData(size: number, pageNum: number, others) {
    this.oldSize = size;
    if (!_.isEqual(this.params, others)) {
      this.params = { ...this.params, ...others };
      this.isGetAll = false;
    }
    if (_.isEmpty(others)) {
      this.params = others;
      this.isGetAll = true;
    }
    this.pageIndex = pageNum;
    this.loadingData = true;
    this._sub = this.apiService.materialsData(this.apiIdentity,
      { ...{ size }, ...{ pageNum }, ...this.params })
      .pipe(timeout(25000))
      .subscribe(res => {
        if (!_.isEmpty(res)) {
          this.itemsTotal = res.totalCount;
          this.displayData = res.data;
          this.allowEdit = _.isNil(res.modifyRight) ? 1 : res.modifyRight;
          this.loadingData = false;
          this.isUpdate = true;
          this.refreshStatus();
        }
      }, err => this.errorHandle(err));
  }

  getSubData() {
    if (this.apiIdentity == 'goodslist' || this.apiIdentity == 'warehouse' ||
      this.apiIdentity == 'checkstocks' || this.apiIdentity == 'stockstat') {
      this.materialsType().subscribe(res => {
        if (_.isArray(res)) {
          this.typeTreeData = res;
          this.convenienceDataC = res[0].children;
        }
      });
      if (this.apiIdentity != 'goodslist') {
        this.allWarehouse().subscribe(res => {
          if (_.isArray(res)) {
            this.warehouseTreeData = res;
            this.convenienceDataW = res[0].children;
          }
        });
      }
    }
  }

  // 获取所有仓库
  allWarehouse() {
    const url = environment.apiBase + '/csmis/mt/mtTwarehouse/orgWarehouseTree.jwt';
    return this.http.get(url);
  }
  // 物资类型获取
  materialsType() {
    const url = environment.apiBase + '/csmis/probdict/data.jwt?dictID=7329de822549448abddc753937d56f7f&isGroup=1&treeType=1';
    return this.http.get(url);
  }

  sort(sorting) {
    this.sortName = sorting.key;
    this.sortValue = sorting.value;
    if (this.sortName && this.sortValue) {
      this.displayData = this.displayData
        .sort(
          (a, b) => (this.sortValue == 'ascend') ?
            (a[this.sortName] > b[this.sortName] ? 1 : -1) :
            (b[this.sortName] > a[this.sortName] ? 1 : -1)
        );
    }
  }

  remoteSort(value: string, valArr) {
    const param = {};
    if (value == 'descend') {
      value = valArr[1];
    } else if (value == 'ascend') {
      value = valArr[0];
    }
    value && (param[this.sortKey] = value);
    this.getMainData(this.pageSize, this.pageIndex, param);
  }

  // 数据获取失败错误提示
  errorHandle(response) {
    this.message.error(JSON.stringify(response), { nzDuration: 1500 });
    this.loadingData = false;
  }

  cachesFn(fn) {
    const caches = Object.create(null);
    return (...argus) => {
      const args = JSON.stringify(argus);
      return caches[args] || (caches[args] = fn.apply(argus));
    };
  }

  // 排序并添加合并属性
  sortAndMerge(rawDataList: any[]): any[] {
    const rowspan = this.rowspan;
    const mergeColumns = this.mergeColumns;
    if (rawDataList.length > 1) {
      const sortColumn = Object.keys(rawDataList[0]),
        keySort = raw => {
          for (let i = raw.length - 1; i > 0; i--) {
            const newObj = {}, tmpObj = raw[i];
            sortColumn.forEach(s => newObj[s] = tmpObj[s]);
            raw[i] = newObj;
          }
          return raw;
        }, compare = (a, b, c = sortColumn[0], i = 0): number => {
          if (a[c] == b[c]) { // 等于的话进行判断是否还有后续字段需要排序，没有则返回0；有则递归进行后续字段排序处理。
            if (i == sortColumn.length - 1) {// 没有后续字段
              return i = 0;
            }
            i++;
            return compare(a, b, sortColumn[i], i); // 递归排序后续字段
          } else if (a[c] > b[c]) { // 大于返回1
            return 1;
          } else { // 小于返回-1
            return -1;
          }
        }, arr = keySort(JSON.parse(JSON.stringify(rawDataList))).sort(compare), aLen = arr.length;
      for (let i = mergeColumns.length - 1; i >= 0; i--) {
        let index = 0;
        const title = mergeColumns[i];
        let span = 1;
        for (let j = 0; j < aLen; j++) {
          const comp = arr[index][title];
          if (arr[j][title] == comp) {
            j != index && (delete arr[j][title], span++);
            j == aLen - 1 && (arr[index][rowspan + title] = span);
          } else {
            span > 1 && (arr[index][rowspan + title] = span, span = 1);
            index = j;
          }
        }
      }
      return arr;
    }
    return rawDataList;
  }

  // 获取接口数据提示
  remoteMessage(response) {
    if (response.type === 'success') {
      this.message.success(response.message, { nzDuration: 1800 });
    } else if (response.type === 'fail') {
      this.message.warning(response.message, { nzDuration: 1500 });
    }
    this.getMainData(this.pageSize, 1, {});
  }

  ngDoCheck() {
    // 返回上一级也要重新获取数据
    this.subscription = this.ums.getMessage().subscribe(
      (message: any) =>
        this.isUpdate && message && message.changed &&
        (
          this.getMainData(this.pageSize, 1, {}),
          this.ums.clearMessage(),
          this.isUpdate = false
        )
    );
  }

  ngOnDestroy() {
    this._sub.unsubscribe();
    this.subscription.unsubscribe();
  }
}
